package org.beetl.sql.btye;

import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.assertj.core.util.Lists;
import org.beetl.sql.annotation.entity.AssignID;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;

public class ByteBuddyExample {
	
	 // Cache for storing modified classes to avoid redundant operations
    private static final ConcurrentHashMap<Class<?>, Class<?>> modifiedClasses = new ConcurrentHashMap<>();

    public static Class<?> addAssignIDAnnotationToFields(Class<?> originalClass, List<String> fieldNames) throws Exception {
        // Check cache first
        return modifiedClasses.computeIfAbsent(originalClass, clazz -> {
            try {
                // Use Byte Buddy to redefine the class with annotations added to the specified fields
                ByteBuddy byteBuddy = new ByteBuddy();
                DynamicType.Builder<?> builder = byteBuddy.redefine(clazz);

                boolean modified = false;

                // Iterate over each field that needs the annotation
                for (String fieldName : fieldNames) {
                    Field field = clazz.getDeclaredField(fieldName);

                    // If the field doesn't have the annotation, add it
                    if (!field.isAnnotationPresent(AssignID.class)) {
                        builder = builder.field(ElementMatchers.named(fieldName))
                                         .annotateField(AnnotationDescription.Builder
                                         .ofType(AssignID.class)
                                         .build());
                        modified = true;
                    }
                }

                // If no fields were modified, return the original class
                if (!modified) {
                    return clazz;
                }

                // Load the modified class using the current thread's ClassLoader
                return builder.make()
                              .load(Thread.currentThread().getContextClassLoader(),ClassReloadingStrategy.fromInstalledAgent())
                              .getLoaded();

            } catch (NoSuchFieldException | IllegalStateException e) {
                throw new RuntimeException("Failed to modify the class", e);
            }
        });
    }

    public static void main(String[] args) throws Exception {
        // Fields to annotate
        List<String> fieldsToAnnotate = Lists.newArrayList("name", "id");

        // Modify MyBean class to add @AssignID annotation to "name" and "id" fields
        Class<?> modifiedClass = addAssignIDAnnotationToFields(MyBean.class, fieldsToAnnotate);

        // Verify the annotations were added
        for (String fieldName : fieldsToAnnotate) {
            Field field = modifiedClass.getDeclaredField(fieldName);
            if (field.isAnnotationPresent(AssignID.class)) {
                System.out.println("Field '" + fieldName + "' has @AssignID annotation.");
            } else {
                System.out.println("Field '" + fieldName + "' does not have @AssignID annotation.");
            }
        }
    }

}
